package logic

import (
	"context"
	"fmt"
	"github.com/zeromicro/go-zero/core/stores/sqlx"
	"good_rpc/models"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"time"

	"good_rpc/internal/svc"
	"good_rpc/pb/good"

	"github.com/zeromicro/go-zero/core/logx"
)

type BatchStockConfirmLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewBatchStockConfirmLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BatchStockConfirmLogic {
	return &BatchStockConfirmLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *BatchStockConfirmLogic) BatchStockConfirm(in *good.StockRequest) (*good.Empty, error) {
	var lastErr error
	goodQuery := "SELECT * FROM good WHERE id = ?"
	updateQuery := "UPDATE good SET stock = stock - ?, version = version + 1 WHERE id = ? AND version = ?"

	for attempt := 0; attempt < l.svcCtx.Config.Stock.MaxRetries; attempt++ {
		err := l.svcCtx.Conn.TransactCtx(l.ctx, func(ctx context.Context, session sqlx.Session) error {
			for _, v := range in.Stocks {
				// 查询当前商品信息
				var info models.Good
				err := session.QueryRowCtx(ctx, &info, goodQuery, v.GoodId)
				if err != nil {
					l.Logger.Errorf("BatchStock failed: good_id=%d, err: %v", v.GoodId, err)
					return fmt.Errorf("查询商品失败: %w", err)
				}

				// 检查库存
				if info.Stock < v.GoodCount {
					l.Logger.Errorf("BatchStock stock failed: good_id=%d, stock=%d, count=%d, err: %v", v.GoodId, info.Stock, v.GoodCount, err)
					return fmt.Errorf("查询库存不足")
				}

				// 执行乐观锁更新
				result, err := session.ExecCtx(ctx, updateQuery, v.GoodCount, v.GoodId, info.Version)
				if err != nil {
					l.Logger.Errorf("BatchStock update stock failed: good_id=%d, err: %v", v.GoodId, err)
					return status.Error(codes.Aborted, "更新库存失败")
				}

				// 检查更新是否成功（版本是否匹配）
				rowsAffected, err := result.RowsAffected()
				if err != nil {
					l.Logger.Errorf("BatchStock update get affected failed: good_id=%d, err: %v", v.GoodId, err)
					return status.Error(codes.Aborted, "获取更新行数失败")
				}

				if rowsAffected == 0 {
					l.Logger.Errorf("BatchStock update abort failed: good_id=%d, err: %v", v.GoodId, err)
					return status.Error(codes.Aborted, "库存已被其他操作修改，请重试")
				}
			}
			return nil
		})

		if err == nil {
			return &good.Empty{}, nil // 成功提交事务
		}

		l.Logger.Errorf("BatchStockConfirm failed: err: %v", err)

		// 检查是否为可重试错误
		st, ok := status.FromError(err)
		if ok && st.Code() == codes.Aborted {
			lastErr = err
			delay := l.svcCtx.Config.Stock.RetryDelay * (1 << attempt)
			time.Sleep(delay)
			continue
		}

		// 非重试错误，直接返回
		return &good.Empty{}, err
	}

	// 重试次数耗尽
	l.Logger.Errorf("BatchStock update retry failed: err: %v", lastErr)
	return &good.Empty{}, fmt.Errorf("库存扣减失败，重试次数耗尽: %w", lastErr)
}
